﻿using System;
using System.Collections.Generic;
using Habanero.Base;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using Habanero.BO.Loaders;
using Habanero.UI.Base;
using Habanero.UI.Win;
using UseCaseManager.BO;
using NUnit.Framework;
using UseCaseManager.Test.BO;
using UseCaseManager.UI;

namespace UseCaseManager.Test.UI
{
    
    /// <summary>
    /// This is a test class for testing the <see cref="UseCasesSelectorControl"/>
    /// </summary>
    [TestFixture]
    public class TestUseCasesSelectorControl
    {
        [TestFixtureSetUp]
        public void SetupTestFixture()
        {
            //Executes once for all tests in this fixture
            //BORegistry.DataAccessor = new DataAccessorDB();
            ClassDef.ClassDefs.Clear();
            ClassDef.LoadClassDefs(new XmlClassDefsLoader(BOBroker.GetClassDefsXml(), new DtdLoader()));
        }

        [SetUp]
        public void TestSetup()
        {
            //Test Setup Runs prior to each test in this fixture executing.
            BORegistry.DataAccessor = new DataAccessorInMemory();
            TestUtils.ClearAllTables();
            BusinessObjectManager.Instance.ClearLoadedObjects();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GlobalUIRegistry.ControlFactory = new ControlFactoryWin(); 
        }

        [Test]
        public void Test_CreateUseCaseSelectorControl_WithNoDrop()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            UseCasesSelectorControl selector = new UseCasesSelectorControl();
            //---------------Test Result -----------------------
            Assert.IsNotNull(selector);
            Assert.IsNull(selector.DropBeingAssigned);
            Assert.IsNotNull(selector.UseCaseMultiSelector);
            Assert.IsNotNull(selector.SaveButton);
            //Assert.IsNotNull(selector.ExportDropsButton);
        }
        
        [Test]
        public void Test_CreateUseCaseSelectorControl()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            UseCasesSelectorControl selector = new UseCasesSelectorControl(drop);
            //---------------Test Result -----------------------
            Assert.IsNotNull(selector);
            Assert.IsNotNull(selector.DropBeingAssigned);
            Assert.IsNotNull(selector.UseCaseMultiSelector);
            Assert.IsNotNull(selector.SaveButton);
            //Assert.IsNotNull(selector.ExportDropsButton);
        }

        [Test]
        public void Test_CreateUseCaseSelectorControl_DropNull()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new UseCasesSelectorControl(null);
                Assert.Fail("expected ArgumentNullException");
            }
                //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("drop", ex.ParamName);
            }
        }

        [Test]
        public void Test_CreateUseCaseSelectorControl_BorderLayoutManagerSetup()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            const int expectedWidth = 223;
            const int expectedHeight = 355;
            const int defaultButtonHeight = 23;
            UseCasesSelectorControl selector = new UseCasesSelectorControl(drop) { Width = expectedWidth, Height = expectedHeight };
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedWidth, selector.UseCaseMultiSelector.Width);
            Assert.AreEqual(defaultButtonHeight, selector.SaveButton.Height);
            Assert.AreEqual(0, selector.UseCaseMultiSelector.Top);
            Assert.AreEqual(expectedHeight - selector.SaveButton.Height - 10, selector.UseCaseMultiSelector.Height);
        }

        [Test]
        public void Test_UseCaseSelectorControl_ChangeSize_MultiSelectorChangesSize()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            UseCasesSelectorControl selector = new UseCasesSelectorControl(drop) { Width = 544, Height = 877 };
            const int expectedWidth = 223;
            const int expectedHeight = 355;
            const int defaultButtonHeight = 23;
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(expectedWidth, selector.UseCaseMultiSelector.Width);
            Assert.AreEqual(defaultButtonHeight, selector.SaveButton.Height);
            Assert.AreEqual(0, selector.UseCaseMultiSelector.Top);
            Assert.AreNotEqual(expectedHeight - selector.SaveButton.Height - 10, selector.UseCaseMultiSelector.Height);
            //---------------Execute Test ----------------------
            selector.Width = expectedWidth;
            selector.Height = expectedHeight;
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedWidth, selector.UseCaseMultiSelector.Width);
            Assert.AreEqual(defaultButtonHeight, selector.SaveButton.Height);
            Assert.AreEqual(0, selector.UseCaseMultiSelector.Top);
            Assert.AreEqual(expectedHeight - selector.SaveButton.Height - 10, selector.UseCaseMultiSelector.Height);
        }

        [Test]
        public void Test_CreateUseCaseSelectorControl_BorderLayoutManagerSetup_WithNoDrop()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            const int expectedWidth = 223;
            const int expectedHeight = 355;
            const int defaultButtonHeight = 23;
            UseCasesSelectorControl selector = new UseCasesSelectorControl { Width = expectedWidth, Height = expectedHeight };
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedWidth, selector.UseCaseMultiSelector.Width);
            Assert.AreEqual(defaultButtonHeight, selector.SaveButton.Height);
            Assert.AreEqual(0, selector.UseCaseMultiSelector.Top);
            Assert.AreEqual(expectedHeight - selector.SaveButton.Height - 10, selector.UseCaseMultiSelector.Height);
        }

        [Test]
        public void Test_LoadsListOfAvailableUseCases()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();

            UseCase useCase = TestUtilsUseCase.CreateSavedUseCase();
            BusinessObjectCollection<UseCase> useCaseCol = Broker.GetBusinessObjectCollection<UseCase>("");
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, useCaseCol.Count);
            Assert.AreSame(useCase, useCaseCol[0]);
            //---------------Execute Test ----------------------
            UseCasesSelectorControl selector = new UseCasesSelectorControl(drop);
            //---------------Test Result -----------------------
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            int noItemsInAvailableList = multiSelector.AvailableOptionsListBox.Items.Count;
            Assert.AreEqual(useCaseCol.Count, noItemsInAvailableList);
            Assert.AreEqual(useCaseCol.Count, multiSelector.AllOptions.Count);
            Assert.AreSame(useCase, multiSelector.Model.AllOptions[0]);
            Assert.AreSame(useCase, multiSelector.Model.AvailableOptions[0]);
        }

        [Test]
        public void Test_LoadsListOfAvailableUseCases_TwoItems()
        {
            //---------------Set up test pack-------------------
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            TestUtilsUseCase.CreateSavedUseCase();
            TestUtilsUseCase.CreateSavedUseCase();
            BusinessObjectCollection<UseCase> useCaseCol = Broker.GetBusinessObjectCollection<UseCase>("");
            //---------------Assert Precondition----------------
            Assert.AreEqual(2, useCaseCol.Count);
            //---------------Execute Test ----------------------
            UseCasesSelectorControl selector = new UseCasesSelectorControl(drop);
            //---------------Test Result -----------------------
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            int noItemsInAvailableList = multiSelector.AvailableOptionsListBox.Items.Count;
            Assert.AreEqual(useCaseCol.Count, noItemsInAvailableList);
            Assert.AreEqual(useCaseCol.Count, multiSelector.AllOptions.Count);
        }

        [Test]
        public void Test_Release_UpdateState()
        {
            //---------------Set up test -----------------------
            UseCasesSelectorControl control= new UseCasesSelectorControl(); 
            //---------------Assert pre conditions -------------

            //---------------Execute Test ----------------------

            //---------------Test Result -----------------------

        }

 
        [Test]
        public void Test_LoadsListOfAvailableUseCases_TwoItems_OneAssociatedWithDrop()
        {
            //---------------Set up test pack-------------------
            Drop drop = CreateDrop_AssociatedWithOneUseCase_OneUseCaseAvailable();
            BusinessObjectCollection<UseCase> useCaseCol = Broker.GetBusinessObjectCollection<UseCase>("");
            //---------------Assert Precondition----------------
            Assert.AreEqual(2, useCaseCol.Count);
            Assert.AreEqual(1, drop.UseCases.Count);
            //---------------Execute Test ----------------------
            UseCasesSelectorControl selector = new UseCasesSelectorControl(drop);
            //---------------Test Result -----------------------
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            int noItemsInAvailableList = multiSelector.AvailableOptionsListBox.Items.Count;
            var noUseCasesNotAssociatedwithTheDrop = 1;
            Assert.AreEqual(noUseCasesNotAssociatedwithTheDrop, noItemsInAvailableList);
            const int noUseCasesAssociatedWithDrop = 1;
            Assert.AreEqual(noUseCasesAssociatedWithDrop, multiSelector.SelectedOptionsListBox.Items.Count);
            const int allUseCasesInAvailableAndSelectedItems = 2;
            Assert.AreEqual(allUseCasesInAvailableAndSelectedItems, multiSelector.AllOptions.Count);
        }

        [Test]
        public void Test_LoadsListOfAvailableUseCases_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop()
        {
            //---------------Set up test pack-------------------
            Drop drop = CreateDrop_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop();
            BusinessObjectCollection<UseCase> useCaseCol = Broker.GetBusinessObjectCollection<UseCase>("");
            BusinessObjectCollection<UseCase> unassignedUseCases = Broker.GetBusinessObjectCollection<UseCase>("DropID IS NULL");
            const int totalNumberOfUseCases = 6;
            const int numUseCasesnotAssigned = 3;
            const int numUseCasesAssignedToThisDrop = 2;
            //---------------Assert Precondition----------------
            Assert.AreEqual(totalNumberOfUseCases, useCaseCol.Count);
            Assert.AreEqual(numUseCasesnotAssigned, unassignedUseCases.Count);
            Assert.AreEqual(numUseCasesAssignedToThisDrop, drop.UseCases.Count);
            //---------------Execute Test ----------------------
            UseCasesSelectorControl selector = new UseCasesSelectorControl(drop);
            //---------------Test Result -----------------------
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            int noItemsInAvailableList = multiSelector.AvailableOptionsListBox.Items.Count;
            Assert.AreEqual(numUseCasesnotAssigned, noItemsInAvailableList);
            const int allUseCasesInAvailableAndSelectedItems = numUseCasesnotAssigned + numUseCasesAssignedToThisDrop;
            Assert.AreEqual(numUseCasesAssignedToThisDrop, multiSelector.SelectedOptionsListBox.Items.Count);
            Assert.AreEqual(allUseCasesInAvailableAndSelectedItems, multiSelector.AllOptions.Count);
        }

        [Test]
        public void Test_LoadsListOfAvailableUseCases_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop_AssignDrop()
        {
            //---------------Set up test pack-------------------
            Drop drop = CreateDrop_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop();
            BusinessObjectCollection<UseCase> useCaseCol = Broker.GetBusinessObjectCollection<UseCase>("");
            BusinessObjectCollection<UseCase> unassignedUseCases = Broker.GetBusinessObjectCollection<UseCase>("DropID IS NULL");
            const int totalNumberOfUseCases = 6;
            const int numUseCasesnotAssigned = 3;
            const int numUseCasesAssignedToThisDrop = 2;
            UseCasesSelectorControl selector = new UseCasesSelectorControl();
            //---------------Assert Precondition----------------
            Assert.AreEqual(totalNumberOfUseCases, useCaseCol.Count);
            Assert.AreEqual(numUseCasesnotAssigned, unassignedUseCases.Count);
            Assert.AreEqual(numUseCasesAssignedToThisDrop, drop.UseCases.Count);
            //---------------Execute Test ----------------------
            selector.DropBeingAssigned = drop;
            //---------------Test Result -----------------------
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            int noItemsInAvailableList = multiSelector.AvailableOptionsListBox.Items.Count;
            Assert.AreEqual(numUseCasesnotAssigned, noItemsInAvailableList);
            const int allUseCasesInAvailableAndSelectedItems = numUseCasesnotAssigned + numUseCasesAssignedToThisDrop;
            Assert.AreEqual(numUseCasesAssignedToThisDrop, multiSelector.SelectedOptionsListBox.Items.Count);
            Assert.AreEqual(allUseCasesInAvailableAndSelectedItems, multiSelector.AllOptions.Count);
        }

        [Test]
        public void Test_SetDropToNull()
        {
            //---------------Set up test pack-------------------
            Drop drop = CreateDrop_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop();
            const int numUseCasesnotAssigned = 3;
            const int numUseCasesAssignedToThisDrop = 2;
            UseCasesSelectorControl selector = new UseCasesSelectorControl();
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            selector.DropBeingAssigned = drop;
            int noItemsInAvailableList = multiSelector.AvailableOptionsListBox.Items.Count;
            const int allUseCasesInAvailableAndSelectedItems = numUseCasesnotAssigned + numUseCasesAssignedToThisDrop;
            //---------------Assert Precondition----------------
            Assert.AreEqual(numUseCasesnotAssigned, noItemsInAvailableList);
            Assert.AreEqual(numUseCasesAssignedToThisDrop, multiSelector.SelectedOptionsListBox.Items.Count);
            Assert.AreEqual(allUseCasesInAvailableAndSelectedItems, multiSelector.AllOptions.Count);
            //---------------Execute Test ----------------------
            selector.DropBeingAssigned = null;
            //---------------Test Result -----------------------
            Assert.IsNull(selector.DropBeingAssigned);
            Assert.AreEqual(0, multiSelector.SelectedOptionsListBox.Items.Count);
            Assert.AreEqual(0, multiSelector.AllOptions.Count);
            Assert.AreEqual(0, multiSelector.AvailableOptionsListBox.Items.Count);
        }

        [Test]
        public void Test_SetDrop_SelectOneItem_Save()
        {
            //---------------Set up test pack-------------------
            Drop drop = CreateDrop_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop();
            const int numUseCasesnotAssigned = 3;
            const int numUseCasesAssignedToThisDrop = 2;
            UseCasesSelectorControl selector = new UseCasesSelectorControl();
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            selector.DropBeingAssigned = drop;
            int noItemsInAvailableList = multiSelector.AvailableOptionsListBox.Items.Count;
            const int allUseCasesInAvailableAndSelectedItems = numUseCasesnotAssigned + numUseCasesAssignedToThisDrop;
            multiSelector.AvailableOptionsListBox.SelectedIndex = 1;
            multiSelector.GetButton(MultiSelectorButton.Select).PerformClick();
            //---------------Assert Precondition----------------
            Assert.AreEqual(numUseCasesAssignedToThisDrop + 1, multiSelector.SelectedOptionsListBox.Items.Count);
            Assert.AreEqual(numUseCasesAssignedToThisDrop + 1, multiSelector.Model.SelectedOptions.Count);
            Assert.AreEqual(allUseCasesInAvailableAndSelectedItems, multiSelector.AllOptions.Count);
            List<UseCase> availableOptions = multiSelector.Model.AvailableOptions;
            Assert.AreEqual(noItemsInAvailableList - 1, availableOptions.Count);
            //---------------Execute Test ----------------------
            selector.SaveButton.PerformClick();
            //---------------Test Result -----------------------
            Assert.AreEqual(numUseCasesAssignedToThisDrop + 1, drop.UseCases.Count, "The UseCase we moved across should now be in the drop.UseCases");
            AssertAllUseCasesHaveNewDropIDSaved(drop);
        }
        
        [Test]
        public void Test_SetDrop_RemoveOneItem_Save()
        {
            //---------------Set up test pack-------------------
            Drop drop = CreateDrop_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop();
            const int numUseCasesnotAssigned = 3;
            const int numUseCasesAssignedToThisDrop = 2;
            UseCasesSelectorControl selector = new UseCasesSelectorControl();
            IMultiSelector<UseCase> multiSelector = selector.UseCaseMultiSelector;
            selector.DropBeingAssigned = drop;
            int noItemsInSelectedList = multiSelector.SelectedOptionsListBox.Items.Count;
            const int allUseCasesInAvailableAndSelectedItems = numUseCasesnotAssigned + numUseCasesAssignedToThisDrop;
            multiSelector.SelectedOptionsListBox.SelectedIndex = 1;
            multiSelector.GetButton(MultiSelectorButton.Deselect).PerformClick();
            //---------------Assert Precondition----------------
            Assert.AreEqual(numUseCasesAssignedToThisDrop-1, multiSelector.SelectedOptionsListBox.Items.Count);
            Assert.AreEqual(numUseCasesAssignedToThisDrop-1, multiSelector.Model.SelectedOptions.Count);
            Assert.AreEqual(allUseCasesInAvailableAndSelectedItems, multiSelector.AllOptions.Count);
            List<UseCase> selectedOptions = multiSelector.Model.SelectedOptions;
            Assert.AreEqual(noItemsInSelectedList-1, selectedOptions.Count);
            //---------------Execute Test ----------------------
            selector.SaveButton.PerformClick();
            //---------------Test Result -----------------------
            Assert.AreEqual(numUseCasesAssignedToThisDrop-1, drop.UseCases.Count, "The UseCase we deselected should no longer be in the drop.UseCases");
            AssertAllUseCasesHaveNewDropIDSaved(drop);
        }

        private static void AssertAllUseCasesHaveNewDropIDSaved(Drop drop)
        {
            foreach (UseCase useCase in drop.UseCases.Clone())
            {
                IBOProp dropIDProp = useCase.Props["DropID"];
                Assert.IsFalse(dropIDProp.IsDirty, "Use Case : " + useCase + " DropID was not saved and is still dirty");
                Assert.AreEqual(drop.DropID, dropIDProp.Value);
            }
        }

        private static Drop CreateDrop_SixUseCases_TwoAssociatedWithDrop_OneWithAnotherDrop()
        {
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            drop.UseCases.Add(TestUtilsUseCase.CreateSavedUseCase());
            drop.UseCases.Add(TestUtilsUseCase.CreateSavedUseCase());
            drop.Save();
            drop.UseCases.SaveAll();
            Drop anotherDrop = TestUtilsDrop.CreateUnsavedValidDrop(); 
            anotherDrop.UseCases.Add(TestUtilsUseCase.CreateSavedUseCase());
            anotherDrop.Save();
            anotherDrop.UseCases.SaveAll();
            TestUtilsUseCase.CreateUnsavedValidUseCase().Save();
            TestUtilsUseCase.CreateUnsavedValidUseCase().Save();
            TestUtilsUseCase.CreateUnsavedValidUseCase().Save();
            return drop;
        }

        private static Drop CreateDrop_AssociatedWithOneUseCase_OneUseCaseAvailable()
        {
            Drop drop = TestUtilsDrop.CreateUnsavedValidDrop();
            drop.UseCases.Add(TestUtilsUseCase.CreateSavedUseCase());
            TestUtilsUseCase.CreateSavedUseCase();
            return drop;
        }
    }
}